package com.nan.gbd.library.codec;

import android.content.Context;
import android.media.MediaFormat;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

import com.nan.gbd.library.JNIBridge;
import com.nan.gbd.library.StatusCallback;
import com.nan.gbd.library.codec.audio.AudioUtils;
import com.nan.gbd.library.codec.configuration.AudioConfiguration;
import com.nan.gbd.library.codec.audio.AudioPlayer;
import com.nan.gbd.library.codec.configuration.Configuration;
import com.nan.gbd.library.codec.surface.CameraSurfaceView;
import com.nan.gbd.library.sip.GBEvent;
import com.nan.gbd.library.sip.MediaOutput;
import com.nan.gbd.library.utils.Logger;
import com.nan.gbd.library.utils.MainThreadManager;

import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public abstract class BaseGBMedia implements StatusCallback {
    public MediaCodecConfig mediaCodecConfig;
    protected Context mContext;
    protected CameraSurfaceView cameraSurfaceView;
    protected WindowManager.LayoutParams params;
    protected WindowManager mWindowManager;
    protected FrameLayout mFloatView;
    /**
     * 声音播放
     */
    protected Map<Integer, AudioPlayer> mAudioPlayers;
    /**
     * 是正在执行任务中
     */
    protected volatile boolean isRunning = false;
    /**
     * 是否正在录制
     */
    protected volatile boolean isRecording = false;
    /**
     * 是否正在直播
     */
    protected volatile boolean isLiving = false;
    /**
     * 是否正在回放中
     */
    protected volatile boolean isPlayback = false;
    /**
     * 是否正在下载中
     */
    protected volatile boolean isDownload = false;

    /**
     * 停止信号来源
     */
    protected volatile boolean isStopFormServer = false;

    /**
     * 是否开启音视频推流
     */
    protected boolean mEnableVideo = true, mEnableAudio = true;

    public void init() {
        this.mContext = Configuration.get().getmContext();
        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        initMediaCodecConfig();
        setAvQueueSize(mediaCodecConfig.getmAvQueueSize());
        setThreadNum(mediaCodecConfig.getmThreadNum());
        setVideoBitrateFactor(mediaCodecConfig.getmVideoBitrateFactor());
        setVideoBitrateAdjustPeriod(mediaCodecConfig.getmVideoBitrateAdjustPeriod());
        setStreamStatPeriod(mediaCodecConfig.getmStreamStatPeriod());
        setProfile(mediaCodecConfig.getProfile());
        setBitrateMode(mediaCodecConfig.getBitrateMode());
        setEnCodecType(mediaCodecConfig.getVencodec());
        setStreamStatPeriod(mediaCodecConfig.getmStreamStatPeriod());
        initAudioFrameLen();
    }

    /**
     * 设置摄像头参数
     */
    public void initMediaCodecConfig() {
        String videoType = MediaFormat.MIMETYPE_VIDEO_AVC;
        String audioType = MediaFormat.MIMETYPE_AUDIO_AAC;
        MediaCodecConfig.Builder builder = new MediaCodecConfig.Builder()
                .setFrameRate(30)
                .setIframeInterval(5)
                .setmThreadNum(-1)
                .setmAvQueueSize(10)
                .setmStreamStatPeriod(3)
                .setmVideoBitrateFactor(0.3)
                .setmVideoBitrateAdjustPeriod(10)
                .setProfile("baseline")
                .setBitrateMode("cq")
                .setVencodec("none")//h264 h265 none
                .setVideoType(videoType)

                .setAudioType(audioType)
                .setAudioFormat(16)
                .setSampleRate(8000)
                .setChannelCount(1)
                .setMaxInputSize(8192)
                .setBitRate(96000);
        Logger.e("参数设置：" + builder.toString());
        mediaCodecConfig = builder.builder();
    }

    //开始推流
    protected abstract void startPushMedia(int key, byte[] param);

    //停止推流
    protected abstract void stopPushMedia();

    //开始录制
    protected abstract void startRecordMedia();

    //停止录制
    protected abstract void stopRecordMedia();

    //播放控制
    protected abstract void playMediaControl(int key, byte[] param);

    //开始播放语音
    protected abstract void startPlayVoiceMedia(int key);

    //停止播放语音
    protected abstract void endPlayVoiceMedia(int key);

    //接收语音数据
    protected abstract void playVoiceMediaData(int key, byte[] param);

    @Override
    public boolean onCallback(int code, String name, int key, byte[] param) {

        switch (code) {
            case GBEvent.GB_DEVICE_EVENT_CONNECTING:
                Logger.e("注册连接中");
                Log.w("native", "注册连接中");
                break;
            case GBEvent.GB_DEVICE_EVENT_REGISTERING:
                Logger.e("注册正在开始中");
                Log.w("native", "注册正在开始中");
                break;
            case GBEvent.GB_DEVICE_EVENT_REGISTER_OK:
                Logger.e("注册成功");
                Log.w("native", "注册成功");
                break;
            case GBEvent.GB_DEVICE_EVENT_REGISTER_AUTH_FAIL:
                Logger.e("注册鉴权失败");
                Log.w("native", "注册鉴权失败");
                break;
            case GBEvent.GB_DEVICE_EVENT_UNREGISTER_OK:
                Logger.e("注销成功");
                Log.w("native", "注销成功");
                break;
            case GBEvent.GB_DEVICE_EVENT_UNREGISTER_FAILED:
                Logger.e("注销失败");
                Log.w("native", "注销失败");
                break;
            case GBEvent.GB_DEVICE_EVENT_START_VIDEO:
                //开始推流
                Logger.e("开始推流");
                startPushMedia(key, param);
                break;
            case GBEvent.GB_DEVICE_EVENT_STOP_VIDEO:
                //停止推流
                Logger.e("停止推流");
                stopPushMedia();
                break;
            case GBEvent.GB_DEVICE_EVENT_START_VOICE:
                //收到对方要发送语音对话事件
                Logger.e("play_voice", "开始语音");
                startPlayVoiceMedia(key);
                break;
            case GBEvent.GB_DEVICE_EVENT_STOP_VOICE:
                //收到对方将结束语音对话事件
                Logger.e("play_voice", "停止语音");
                endPlayVoiceMedia(key);
                break;
            case GBEvent.GB_DEVICE_EVENT_TALK_AUDIO_DATA:
                //播放对方发送的语音
                Logger.e("play_voice", "语音对讲音频数据");
                playVoiceMediaData(key, param);
                break;
            case GBEvent.GB_DEVICE_EVENT_START_RECORD:
                Logger.e("开始录制");
                startRecordMedia();
                break;
            case GBEvent.GB_DEVICE_EVENT_STOP_RECORD:
                Logger.e("停止录制");
                stopRecordMedia();
                break;
            case GBEvent.GB_DEVICE_EVENT_STATISTICS:
                Logger.e("编码和发送统计信息");
                break;
            //录播播放控制
            case GBEvent.GB_DEVICE_EVENT_PLAY_BACK_CONTROL:
                playMediaControl(key, param);
                break;
            case GBEvent.GB_DEVICE_EVENT_DISCONNECT:
                Logger.e("连接断开, 如果正在推流,停止推流");
                Log.w("native", "连接断开, 如果正在推流,停止推流");
                //停止推流
                MainThreadManager.getMainHandler().post(new Runnable() {
                    @Override
                    public void run() {
                        stopPushMedia();
                    }
                });
                break;
            default:
                break;
        }
        return true;
    }

    /**
     * 设置编码线程数
     *
     * @param threadNum 默认-1, 为-1时表示硬编码，
     * 为0时表示软编码自适应线程，>0时表示软编码线程数，最大取值 MAX_THREAD_NUM
     */
    protected int mThreadNum = 5;

    private void setThreadNum(int threadNum) {
        if (threadNum > 0) {
            this.mThreadNum = threadNum;
        }

    }

    /**
     * 设置编码最大缓存队列大小
     *
     * @param size 默认100
     */
    /**
     * 队列大小
     */
    protected static final int QUEUE_MAX_SIZE = 100;
    protected int mAvQueueSize = QUEUE_MAX_SIZE;

    private void setAvQueueSize(int size) {
        if (size > 0) {
            this.mAvQueueSize = size;
        }
    }

    /**
     * 设置视频比特率上下浮动因子
     *
     * @param factor 默认0.3, [0, 1]之间
     */
    protected double mVideoBitrateFactor = 0.3f;

    private void setVideoBitrateFactor(double factor) {
        if (factor > 0f && factor < 1f) {
            this.mVideoBitrateFactor = factor;
        }
    }

    /**
     * 设置视频比特率动态调整周期(秒)
     * 内部会自动计算当前网络发送拥塞程度并根据其进行上下码率调整
     *
     * @param period 默认30, 为0表示不自动调整码率
     */
    protected int mVideoBitrateAdjustPeriod = 30;

    private void setVideoBitrateAdjustPeriod(int period) {
        if (period >= 0) {
            this.mVideoBitrateAdjustPeriod = period;
        }
    }

    /**
     * 设置流状态统计周期(秒)
     *
     * @param period 默认3
     */
    protected int mStreamStatPeriod = 3;

    private void setStreamStatPeriod(int period) {
        if (period >= 0) {
            this.mStreamStatPeriod = period;
        }
    }

    protected int profile = 1;

    public void setProfile(String prof) {
        if ("baseline".equals(prof)) {
            profile = 1;
        } else if ("main".equals(prof)) {
            profile = 2;
        } else if ("high".equals(prof)) {
            profile = 3;
        }
    }

    protected int bitrateMode = 1;

    private void setBitrateMode(String bitrateM) {
        if ("cq".equals(bitrateM)) {
            bitrateMode = 0;
        } else if ("vbr".equals(bitrateM)) {
            bitrateMode = 1;
        } else if ("cbr".equals(bitrateM)) {
            bitrateMode = 2;
        }
    }

    /**
     * 视频编码类型
     */

    public static final int VIDEO_ENCODEC_NONE = 0;
    public static final int VIDEO_ENCODEC_H264 = 1; // h264
    public static final int VIDEO_ENCODEC_H265 = 2; // h265
    protected int vencodec = VIDEO_ENCODEC_NONE;


    private void setEnCodecType(String mEnCodecType) {
        vencodec = VIDEO_ENCODEC_NONE;
        if ("h264".equals(mEnCodecType)) {
            vencodec = VIDEO_ENCODEC_H264;
        } else if ("h265".equals(mEnCodecType)) {
            vencodec = VIDEO_ENCODEC_H265;
        }
    }


    /**
     * 结束语音交流
     *
     * @param cid
     * @return
     */
    public synchronized boolean endVoice(int cid) {
        Logger.e("endVoice " + cid + " pid:" + Thread.currentThread().getId());

        if (null == mAudioPlayers) {
            return false;
        }
        AudioPlayer audioPlayer = mAudioPlayers.get(cid);
        if (null == audioPlayer) {
            Logger.e("not exist voice cid " + cid);
            return false;
        }

        audioPlayer.stop();
        mAudioPlayers.remove(cid);
        return true;
    }

    /**
     * 保存不同的声音来源-并设置相应的播放器
     *
     * @param cid
     * @return
     */
    public synchronized boolean startVoice(int cid) {
        Logger.e("play_voice", "startVoice " + cid + " pid:" + Thread.currentThread().getId());
        if (null == mAudioPlayers) {
            mAudioPlayers = new ConcurrentHashMap<>();
        }
        if (mAudioPlayers.containsKey(cid)) {
            Logger.e("play_voice", "exist voice cid " + cid);
            return false;
        }

        AudioPlayer audioPlayer = new AudioPlayer(onAudioListener);
        mAudioPlayers.put(cid, audioPlayer);
        return audioPlayer.init();
    }

    AudioPlayer.OnAudioListener onAudioListener = new AudioPlayer.OnAudioListener() {
        @Override
        public void onAudioError(int code) {
            String message = getAudioMessage(code);
            Logger.e("play_voice", "onAudioError :" + message);
        }
    };

    /**
     * 获取到来自对方的声音数据--再次播放
     *
     * @param cid
     * @param data
     * @return
     */
    public boolean playVoiceData(int cid, byte[] data) {
        if (null == mAudioPlayers || null == data || data.length == 0) {
            return false;
        }
        AudioPlayer audioPlayer = mAudioPlayers.get(cid);
        if (null == audioPlayer) {
            Logger.e("play_voice", "not exist voice cid " + cid);
            return false;
        }
        return audioPlayer.write(data);
    }

    protected static String getAudioMessage(int code) {
        String res;
        switch (code) {
            case AudioPlayer.AUDIO_ERROR_UNKNOWN:
                res = "start audio record failed";
                break;
            case AudioPlayer.AUDIO_RECORD_ERROR_SAMPLERATE_NOT_SUPPORT:
                res = "sample rate not support";
                break;
            case AudioPlayer.AUDIO_RECORD_ERROR_GET_FRAME_SIZE_NOT_SUPPORT:
                res = "parameters are not supported by the hardware";
                break;
            case AudioPlayer.AUDIO_RECORD_ERROR_CREATE_FAILED:
                res = "new audio record failed";
                break;
            default:
                res = "audio record error";
                break;
        }
        return res;
    }

    HelmetVoiceCallBack helmetVoiceCallBack;

    public void setHelmetVoiceCallBack(HelmetVoiceCallBack helmetVoiceCallBack) {
        this.helmetVoiceCallBack = helmetVoiceCallBack;
    }

    public static interface HelmetVoiceCallBack {
        void playRemindVoice();

        void stopRemindVoice();

        void playLiveVoice();

        void stopLiveVoice();
    }


    public void setEnableVideo(boolean mEnableVideo) {
        this.mEnableVideo = mEnableVideo;
    }

    public void setEnableAudio(boolean mEnableAudio) {
        this.mEnableAudio = mEnableAudio;
    }

    public boolean isRunning() {
        return isRunning;
    }

    public boolean isRecording() {
        return isRecording;
    }

    public boolean isLiving() {
        return isLiving;
    }

    public boolean isPlayback() {
        return isPlayback;
    }


    private void initAudioFrameLen() {
        AudioConfiguration audioConfiguration = AudioConfiguration.createDefault();
        audioFrameLen = AudioUtils.getRecordBufferSize(audioConfiguration);
    }

    protected int audioFrameLen;

    public void setAudioFrameLen(int audioFrameLen) {
        this.audioFrameLen = audioFrameLen;
    }
}
